<template>
  <div class="image-hotarea-editor" :class="{'image-hotarea-editor__empty-image': !hotArea.image}">
    <div class="image-hotarea-editor__inner">
      <div class="image-hotarea-editor__content" @click="handleOpenDialog">
        <img
          :src="hotArea.image.src"
          alt
          class="image-hotarea-editor__content-img"
        />
        <div
          v-for="(area, index) in previewAreas"
          :key="area.__key"
          class="image-hotarea-editor__area"
          :style="{
            transform: `translate(${area.x}px, ${area.y}px)`,
            width: area.width + 'px',
            height: area.height + 'px',
            zIndex: opt_index === index ? 2 : 1
          }"
        >
          <link-selector v-model="area.link" disabled />
        </div>
      </div>
    </div>
    <image-selector v-model="hotArea.image" />
    <el-dialog
      title="热区编辑器"
      :visible.sync="showDialog"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      width="600px"
      style="cursor: auto"
    >
      <div class="image-hotarea-editor__dialog">
        <div class="image-hotarea-editor_steps">
          <span class="step-hotarea">
              <span class="step-num">1</span>
              <span class="step-text">添加热区</span>
              <span>-</span>
            </span>
          <span class="step-hotarea">
              <span class="step-num">2</span>
              <span class="step-text">调整热区大小和位置</span>
              <span>-</span>
            </span>
          <span class="step-hotarea">
              <span class="step-num">3</span>
              <span class="step-text">设置关联链接</span>
              <span>-</span>
            </span>
          <span class="step-hotarea">
              <span class="step-num">4</span>
              <span class="step-text">保存生效</span>
              <span></span>
            </span>
        </div>
        <div
          class="image-hotarea-editor__content"
          @mousemove="handleMousemove($event)"
          @mouseenter="clearOpt"
        >
          <img
            :src="hotArea.image.src"
            alt
            class="image-hotarea-editor__content-img"
            @load="handleImageLoad"
          />
          <div
            v-for="(area, index) in hotArea.hotAreas"
            :key="area.__key"
            class="image-hotarea-editor__area"
            :style="{
              transform: `translate(${area.x}px, ${area.y}px)`,
              zIndex: index + 1,
              width: area.width + 'px',
              height: area.height + 'px',
              zIndex: opt_index === index ? 2 : 1
            }"
            :area-index="index"
            @mousedown="handleMousedown('main', index, $event)"
            @mouseup="clearOpt"
          >
            <div class="image-hotarea-editor__area-del-icon" @click="handleDeleteArea(area, index)">x</div>
            <div class="image-hotarea-editor__area-opts">
              <div
                v-for="(opt, opt_index) in operateSpaces"
                :key="opt_index"
                class="opt-area"
                :style="{
                  top: opt.top,
                  right: opt.right,
                  bottom: opt.bottom,
                  left: opt.left,
                  width: opt.width,
                  height: opt.height,
                  cursor: opt.cursor,
                }"
                @mousedown.stop="handleMousedown(opt.type, index, $event)"
              >
              </div>
            </div>
            <link-selector v-model="area.link" />
          </div>
        </div>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button type="primary" @click="handleAddHotarea">添加热区</el-button>
        <el-button @click="handleSaveHotarea">保存</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  name: 'ImageHotareaEditor',
  props: {
    value: {
      type: [Object, String],
      required: true
    },
    // 是否只读
    readonly: {
      type: Boolean,
      required: false,
      default: false
    }
  },
  model: { event: 'update', prop: 'value' },
  watch: {
    value: {
      immediate: true,
      handler: 'handleDefaultChange'
    },
    'hotArea.image': {
      deep: true,
      handler(newVal) {
        if (!newVal) return
        this.$emit('update', this.hotArea)
      }
    }
  },
  data() {
    return {
      hotArea: '',
      previewAreas: [],
      showDialog: false,
      operateSpaces: [
        { width: '100%', height: '10px', top: '-5px', left: 0, cursor: 'row-resize', type: 'top' },
        { width: '10px', height: '100%', top: 0, right: '-5px', cursor: 'col-resize', type: 'right' },
        { width: '100%', height: '10px', bottom: '-5px', left:0, cursor: 'row-resize', type: 'bottom' },
        { width: '10px', height: '100%', top: 0, left: '-5px', cursor: 'col-resize', type: 'left' },
        { width: '20px', height: '20px', right: '-10px', top: '-10px', cursor: 'ne-resize', type: 'top-right' },
        { width: '20px', height: '20px', right: '-10px', bottom: '-10px', cursor: 'se-resize', type: 'bottom-right' },
        { width: '20px', height: '20px', left: '-10px', bottom: '-10px', cursor: 'sw-resize', type: 'bottom-left' },
        { width: '20px', height: '20px', left: '-10px', top: '-10px', cursor: 'nw-resize', type: 'top-left' }
      ],
      opt_type: '',
      opt_index: 0,
      opt_start_x: 0,
      opt_start_y: 0,
      opt_timer: null,
      opt_max_height: 0,
      throttle_time: 0
    }
  },
  methods: {
    handleOpenDialog() {
      this.showDialog = true
      const { hotAreas } = this.hotArea
      if (!hotAreas || !hotAreas.length) {
        this.handleAddHotarea()
      }
    },
    /**
     * 添加热区
     */
    handleAddHotarea() {
      if (!this.hotArea.hotAreas) {
        this.hotArea.hotAreas = []
      }
      this.hotArea.hotAreas.push({
        __key: this.$$Foundation.uuid(),
        x: 0,
        y: 0,
        width: 115,
        height: 115,
        link: ''
      })
    },
    /**
     * 删除热区
     * @param item
     * @param index
     */
    handleDeleteArea(item, index) {
      this.hotArea.hotAreas.splice(index, 1)
    },
    /**
     * 按下鼠标
     * @param type
     * @param index
     * @param event
     */
    handleMousedown(type, index, event) {
      this.opt_type = type
      this.opt_index = index
      this.opt_start_x = event.clientX
      this.opt_start_y = event.clientY
    },
    /**
     * 热区移动、大小调整
     * @param event
     */
    handleMousemove(event) {
      if (!this.opt_type) return
      let time = this.opt_type === 'main' ? 20 : 10
      if (this.throttle_time && Date.now() - this.throttle_time < time) return
      this.throttle_time = Date.now()
      let moveX = event.clientX - this.opt_start_x
      let moveY = event.clientY - this.opt_start_y
      const area = this.hotArea.hotAreas[this.opt_index]
      switch (this.opt_type) {
        case 'main':
          area.x += moveX;
          area.y += moveY;
          break;
        case 'top':
          area.y += moveY
          area.height -= moveY
          break
        case 'right':
          area.width += moveX
          break
        case 'bottom':
          area.height += moveY
          break
        case 'left':
          area.x += moveX
          area.width -= moveX
          break
        case 'top-right':
          area.y += moveY
          area.width += moveX
          area.height -= moveY
          break
        case 'bottom-right':
          area.width += moveX
          area.height += moveY
          break
        case 'bottom-left':
          area.x += moveX
          area.width -= moveX
          area.height += moveY
          break
        case 'top-left':
          area.x += moveX
          area.y += moveY
          area.width -= moveX
          area.height -= moveY
          break
      }
      if (area.x < 0) area.x = 0
      if (area.y < 0) area.y = 0
      if (area.x > (560 - area.width)) {
        area.x = 560 - area.width
      }
      if (area.y > (this.opt_max_height - area.height)) {
        area.y = this.opt_max_height - area.height
      }
      if (area.width < 65) area.width = 65
      if (area.height < 30) area.height = 30
      this.opt_start_x = event.clientX
      this.opt_start_y = event.clientY
    },
    /**
     * 图片加载完成
     * @param event
     */
    handleImageLoad(event) {
      this.opt_max_height = event.target.offsetHeight
    },
    handleSaveHotarea() {
      this.previewAreas = this.computedHotAreasSize(this.hotArea.hotAreas, 348, 545)
      const hotArea = this.$$Foundation.cloneDeep(this.hotArea)
      hotArea.hotAreas = this.computedHotAreasSize(hotArea.hotAreas, 750, 545)
      this.$emit('update', hotArea)
      this.showDialog = false
    },
    /**
     * 清理操作数据
     */
    clearOpt() {
      this.opt_type = ''
      this.opt_index = 0
      this.opt_start_x = 0
      this.opt_start_y = 0
    },
    /**
     * 计算热区各种大小
     * @param areas
     * @param width
     * @param design_width
     * @returns {*}
     */
    computedHotAreasSize(areas, width, design_width) {
      if (!Array.isArray(areas)) return areas
      const _areas = this.$$Foundation.cloneDeep(areas)
      const ratios = ['width', 'height', 'x', 'y']
      return _areas.map(item => {
        ratios.forEach(key => item[key] = (width / design_width) * item[key])
        return item
      })
    },
    /**
     * 默认值发生改变
     * @param newVal
     */
    handleDefaultChange(newVal) {
      if (this.hotArea) return
      const hotArea = this.$$Foundation.cloneDeep(newVal)
      hotArea.hotAreas = this.computedHotAreasSize(hotArea.hotAreas, 545, 750)
      this.previewAreas = this.computedHotAreasSize(hotArea.hotAreas, 348, 545)
      this.hotArea = hotArea
    }
  }
}
</script>

<style lang="scss" scoped>
.image-hotarea-editor {
  position: relative;
  width: 100%;
  &__inner {
    width: 100%;
    .image-hotarea-editor__content {
      cursor: pointer;
    }
    .image-hotarea-editor__area {
      cursor: pointer !important;
    }
    /deep/ .link-selector .el-input__inner {
      cursor: pointer;
    }
  }
  &__image {
    width: 100%;
    cursor: pointer;
  }
  &__empty-image .image-selector {
    height: 100% !important;
  }
  /deep/ {
    .image-selector {
      position: absolute;
      z-index: 10;
      bottom: 0;
      width: 100%;
      height: 28px;
      border: 0;
      border-radius: 0 0 2px 2px;
    }
    .image-selector__change {
      height: 100%;
      line-height: 28px;
    }
    .image-selector__image-img {
      display: none;
    }
    .el-dialog__body {
      padding: 16px 20px;
    }
    .image-hotarea-editor__dialog {
      max-width: 600px;
      box-sizing: border-box;
    }
    .image-hotarea-editor_steps {
      color: #969799;
      margin-bottom: 12px;
      .step-hotarea {
        margin-right: 10px;
      }
      .step-num {
        display: inline-block;
        width: 24px;
        height: 24px;
        line-height: 24px;
        border: 1px solid #e5e5e5;
        border-radius: 13px;
        text-align: center;
      }
      .step-text {
        margin: 0 10px;
      }
    }
    .image-hotarea-editor__content {
      position: relative;
      max-height: 420px;
      min-height: 50px;
      width: 100%;
      overflow-x: hidden;
      overflow-y: auto;
      &::-webkit-scrollbar {
        display: none;
      }
      .image-hotarea-editor__content-img {
        width: 100%;
        height: 100%;
        user-select: none;
      }
      .image-hotarea-editor__area {
        position: absolute;
        top: 0;
        left: 0;
        color: #ffffff;
        font-size: 12px;
        border: 1px solid #155bd4;
        background-color: rgba(51,136,255,.5);
        cursor: move;
        user-select: auto;
        touch-action: none;
        box-sizing: border-box;
        &:hover .image-hotarea-editor__area-del-icon {
          display: block;
        }
        .image-hotarea-editor__area-del-icon {
          position: absolute;
          top: -8px;
          right: -8px;
          width: 16px;
          height: 16px;
          line-height: 15px;
          border-radius: 9px;
          color: #ffffff;
          text-align: center;
          cursor: pointer;
          background-color: rgba(0,0,0,.5);
          display: none;
          z-index: 2;
        }
      }
      .image-hotarea-editor__area-opts {
        .opt-area {
          position: absolute;
          user-select: none;
        }
      }
      .link-selector {
        position: absolute;
        bottom: 0;
        .el-input__inner {
          background-color: rgba(0,0,0,.5);
          border-radius: 0;
          border: none;
        }
        .el-tag {
          border-right: 0;
          border-bottom: 0;
          border-left: 0;
          border-radius: 0;
        }
      }
    }
  }
}
</style>
